package com.zbkj.crmeb.store.service.impl;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.utils.ThreadPoolUtils;
import com.zbkj.crmeb.enums.BusinessTypeEnums;
import com.zbkj.crmeb.merchant.admin.service.StoreProductStockService;
import com.zbkj.crmeb.store.model.*;
import com.zbkj.crmeb.store.response.StoreCartResponse;
import com.zbkj.crmeb.store.service.*;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.binding.MapperMethod;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.PageParamRequest;
import com.crmeb.core.exception.CrmebException;
import com.github.pagehelper.PageHelper;
import com.zbkj.crmeb.enums.ProductTypeEnum;
import com.zbkj.crmeb.store.dao.StoreProductAttrValueDao;
import com.zbkj.crmeb.store.request.StoreProductAttrValueSearchRequest;
import com.zbkj.crmeb.store.vo.StoreOrderInfoVo;
import com.zbkj.crmeb.system.service.SystemConfigService;

/**
* @author Mr.Zhang edit by stivepeim 7-6
* @description StoreProductAttrValueServiceImpl 接口实现
* @date 2020-05-27
*/
@Slf4j
@Service
public class StoreProductAttrValueServiceImpl extends ServiceImpl<StoreProductAttrValueDao, StoreProductAttrValue>
        implements StoreProductAttrValueService {

    @Resource
    private StoreProductAttrValueDao dao;

    @Autowired
    private StoreProductStockService storeProductStockService;
    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private StoreOrderInfoService storeOrderInfoService;
    @Autowired
    private StoreProductService storeProductService;
    @Resource
    private RelationService relationService;


    /**
    * 列表
    * @param request 请求参数
    * @param pageParamRequest 分页类参数
    * @author Mr.Zhang
    * @since 2020-05-27
    * @return List<StoreProductAttrValue>
    */
    @Override
    public List<StoreProductAttrValue> getList(StoreProductAttrValueSearchRequest request, PageParamRequest pageParamRequest) {
        PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());

        //带 StoreProductAttrValue 类的多条件查询
        LambdaQueryWrapper<StoreProductAttrValue> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        StoreProductAttrValue model = new StoreProductAttrValue();
        BeanUtils.copyProperties(request, model);
        lambdaQueryWrapper.setEntity(model);
        return dao.selectList(lambdaQueryWrapper);
    }

    @Override
    public List<StoreProductAttrValue> listRelationInfoByProductId(List<Integer> productIds, BusinessTypeEnums businessTypeEnums) {
        if (CollectionUtils.isEmpty(productIds)){
            return null;
        }
        List<StoreProductAttrValue> skuList = this.list(Wrappers.<StoreProductAttrValue>lambdaQuery().in(StoreProductAttrValue::getProductId, productIds).eq(StoreProductAttrValue::getType,0));
        if (CollectionUtils.isEmpty(skuList)){
            return null;
        }
        List<Integer> skuIds = skuList.stream().map(StoreProductAttrValue::getId).collect(Collectors.toList());
        List<Relation> skuRelations = relationService.list(Wrappers.<Relation>lambdaQuery().in(Relation::getBusinessCode, skuIds).eq(Relation::getBusinessType, businessTypeEnums.getCode()));
        if (CollectionUtils.isEmpty(skuRelations)){
            return skuList;
        }
        Map<Integer, Relation> skuRelationMap = skuRelations.stream().collect(Collectors.toMap(k -> Integer.valueOf(k.getBusinessCode()), v -> v));
        for (StoreProductAttrValue storeProductAttrValue : skuList) {
            if (!skuRelationMap.containsKey(storeProductAttrValue.getId())){
                continue;
            }
            storeProductAttrValue.setPushRelation(skuRelationMap.get(storeProductAttrValue.getId()));
        }
        return skuList;
    }

    /**
     * 根据商品id获取attrValues
     * @param productId 商品id
     * @return 包含商品id的Attrvalues
     */
    @Override
    public List<StoreProductAttrValue> getListByProductId(Integer productId) {
        LambdaQueryWrapper<StoreProductAttrValue> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StoreProductAttrValue::getProductId, productId)
                .orderByAsc(StoreProductAttrValue::getId);
        List<StoreProductAttrValue> ll = dao.selectList(lambdaQueryWrapper);
        return ll;
    }

    /**
     *
     * @param productId 商品id
     * @param attrId 属性id
     * @return 商品属性集合
     */
    @Override
    public List<StoreProductAttrValue> getListByProductIdAndAttrId(Integer productId, String attrId) {
        LambdaQueryWrapper<StoreProductAttrValue> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StoreProductAttrValue::getProductId, productId);
        if(null != attrId){
            lambdaQueryWrapper.eq(StoreProductAttrValue::getSourceSkuId, attrId);
        }
        List<StoreProductAttrValue> ll = dao.selectList(lambdaQueryWrapper);
        // 补图片
        return ll;
    }

    @Override
    public List<StoreProductAttrValue> getListByProductIdAndSkuId(Integer productId, String skuId) {
        LambdaQueryWrapper<StoreProductAttrValue> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StoreProductAttrValue::getProductId, productId);
        if(null != skuId){
            lambdaQueryWrapper.eq(StoreProductAttrValue::getSourceSkuId, skuId);
        }
        List<StoreProductAttrValue> ll = dao.selectList(lambdaQueryWrapper);
        // 补图片
        return ll;
    }

    /**
     * 根据产品属性查询
     * @param storeProductAttrValue 商品属性参数
     * @return 查询到的属性结果
     */
    @Override
    public StoreProductAttrValue getByEntity(StoreProductAttrValue storeProductAttrValue) {
        LambdaQueryWrapper<StoreProductAttrValue> lqw = new LambdaQueryWrapper<>();
        lqw.setEntity(storeProductAttrValue);
        return dao.selectOne(lqw);
    }

    /**
     * 减库存增加销量
     * @param productId 商品id
     * @param attrValueId 商品attrValue id
     * @param num 销售数量
     * @param type 是否限购
     * @return 操作后的结果标识
     */
    @Override
    public boolean decProductAttrStock(Integer productId, String attrValueId, Integer num, Integer type, Integer activityGroupId) {
        List<StoreProductAttrValue> existAttrValues = getListByProductIdAndSkuId(productId, attrValueId);
//        List<StoreProductAttrValue> existAttrValues = getListByProductIdAndSkuId(productId, attrValueId);
        if(existAttrValues.size() == 0){
            throw new CrmebException("商品已售完");
        }

        StoreProductAttrValue attrValue = existAttrValues.get(0);
        boolean result = false;
        if(null == activityGroupId || 0 == activityGroupId) {
            // 为什么一件的时候不能卖
            if (num > attrValue.getStock()) {
                throw new CrmebException("库存不足");
            }

            LambdaUpdateWrapper<StoreProductAttrValue> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper.eq(StoreProductAttrValue::getProductId, productId);
            lambdaUpdateWrapper.eq(StoreProductAttrValue::getSourceSkuId, attrValueId);
            lambdaUpdateWrapper.eq(StoreProductAttrValue::getType, type);

            if (type == 0) { // 不限购
                lambdaUpdateWrapper.set(StoreProductAttrValue::getStock, attrValue.getStock() - num);
                lambdaUpdateWrapper.set(StoreProductAttrValue::getSales, attrValue.getSales() + num);
                result = update(lambdaUpdateWrapper);
            } else {
                lambdaUpdateWrapper.set(StoreProductAttrValue::getStock, attrValue.getStock() - num);
                lambdaUpdateWrapper.set(StoreProductAttrValue::getSales, attrValue.getSales() + num);
                lambdaUpdateWrapper.set(StoreProductAttrValue::getQuota, attrValue.getStock() - num);
                result = update(lambdaUpdateWrapper);
            }

            if (result) { //判断库存警戒值
                Integer alterNumI = 0;
                String alterNum = systemConfigService.getValueByKey("store_stock");
                if (StringUtils.isNotBlank(alterNum)) alterNumI = Integer.parseInt(alterNum);
                if (alterNumI >= attrValue.getStock()) {
                    // todo socket 发送库存警告
                }

            }
        }else{
            // 扣减拼团库存(对于批采订单，不会处理拼团的库存 TODO DIDIOK)
            log.info("扣减拼团库存， 拼团活动id:{}", activityGroupId);
            try {
                result = storeProductStockService.updateStock(productId, attrValueId, num, type, activityGroupId);
            }catch (Exception e){
                log.error("扣减拼团库存报错:{}", e.fillInStackTrace());
                throw new CrmebException("扣减拼团库存报错，拼团活动的库存不足!");
            }
        }
        return result;
    }

    /**
     * 根据商品id删除AttrValue
     * @param productId 商品id
     * @reture 删除结果
     */
    @Override
    public boolean removeByProductId(Integer productId) {
        LambdaQueryWrapper<StoreProductAttrValue> lambdaQW = new LambdaQueryWrapper<>();
        lambdaQW.eq(StoreProductAttrValue::getProductId, productId);
        return dao.delete(lambdaQW) > 0;
    }

    /**
     * 根据商品id删除AttrValue
     * @param productId 商品id
     * @reture 删除结果
     */
    @Override
    public List<StoreProductAttrValue>  listByProductId(Integer productId) {
        LambdaQueryWrapper<StoreProductAttrValue> lambdaQW = new LambdaQueryWrapper<>();
        lambdaQW.eq(StoreProductAttrValue::getProductId, productId);
        return dao.selectList(lambdaQW);
    }

    @Override
    public void addProductAttrStock(StoreOrder storeOrder) {

        List<StoreOrderInfoVo> infoVoList = storeOrderInfoService.getOrderListByOrderId(storeOrder.getId());
        infoVoList.stream().forEach(info ->{
            StoreProduct storeProduct = storeProductService.getById(info.getProductId());
            if(null!= storeProduct){
                storeProduct.setStock(storeProduct.getStock()+info.getInfo().getCartNum());
                storeProductService.updateById(storeProduct);
            }

            //buyer的商品 查询attrvalue
            if(ProductTypeEnum.BUYER.getCode() == info.getInfo().getProductInfo().getIsEurope()){
                StoreProductAttrValue apAttrValuePram = new StoreProductAttrValue();
                apAttrValuePram.setSourceSkuId(info.getInfo().getProductInfo().getAttrInfo().getSourceSkuId());
                apAttrValuePram.setProductId(info.getProductId());
                apAttrValuePram.setType(0);
                LambdaQueryWrapper<StoreProductAttrValue> lqw = new LambdaQueryWrapper<>();
                lqw.setEntity(apAttrValuePram);
                StoreProductAttrValue attrValue = dao.selectOne(lqw);
                if(null != attrValue){
                    LambdaUpdateWrapper<StoreProductAttrValue> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                    lambdaUpdateWrapper.eq(StoreProductAttrValue::getProductId,info.getProductId());
                    lambdaUpdateWrapper.eq(StoreProductAttrValue::getSourceSkuId, attrValue.getSourceSkuId());
                    lambdaUpdateWrapper.set(StoreProductAttrValue::getStock, attrValue.getStock()+info.getInfo().getCartNum());
                    //lambdaUpdateWrapper.set(StoreProductAttrValue::getSales, attrValue.getSales()-info.getInfo().getCartNum());
                    update(lambdaUpdateWrapper);
                }
            }else{
                StoreProductAttrValue apAttrValuePram = new StoreProductAttrValue();
                apAttrValuePram.setProductId(info.getProductId());
                apAttrValuePram.setBarCode(info.getInfo().getProductInfo().getBarCode());
                apAttrValuePram.setSuk(info.getInfo().getProductInfo().getAttrInfo().getSuk());
                LambdaQueryWrapper<StoreProductAttrValue> lqw = new LambdaQueryWrapper<>();
                lqw.setEntity(apAttrValuePram);
                StoreProductAttrValue attrValue = dao.selectOne(lqw);
                if(null != attrValue){
                    LambdaUpdateWrapper<StoreProductAttrValue> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                    lambdaUpdateWrapper.eq(StoreProductAttrValue::getBarCode, attrValue.getBarCode());
                    lambdaUpdateWrapper.eq(StoreProductAttrValue::getSuk, attrValue.getSuk());
                    lambdaUpdateWrapper.set(StoreProductAttrValue::getStock, attrValue.getStock()+info.getInfo().getCartNum());
                    //lambdaUpdateWrapper.set(StoreProductAttrValue::getSales, attrValue.getSales()-info.getInfo().getCartNum());
                    update(lambdaUpdateWrapper);
                }
            }
        });

    }
    
    @Override
    public Boolean subProductStock(Integer productId,String sourceSkuId,Integer stock) {
        int updateCount = dao.subProductStock(productId,sourceSkuId,stock);
        return 0 > updateCount;
    }

    @Override
    public Boolean subProductStockByJky(String selfSourceSkuId,Integer stock) {
        int updateCount = dao.subProductStockByJky(selfSourceSkuId,stock);
        return 0 > updateCount;
    }

    @Override
    public void addProductValueStock(StoreOrderInfo storeOrderInfo) {
        // 真拼团活动id
        Integer activityGroupId = storeOrderInfo.getActivityGroupId();

        StoreProduct storeProduct = storeProductService.getById(storeOrderInfo.getProductId());
        StoreCartResponse storeCartResponse = JSON.parseObject(storeOrderInfo.getInfo(), StoreCartResponse.class);
        if(null!= storeProduct){
            storeProduct.setStock(storeProduct.getStock()+storeCartResponse.getCartNum());
            storeProductService.updateById(storeProduct);
        }
        // 拼团活动归还库存量
        if(null != activityGroupId && 0 != activityGroupId) {
            log.info("拼团活动归还库存量:{}", activityGroupId);
            try {
                storeProductStockService.refundStock(storeOrderInfo);
            }catch (Exception e){
                log.error("拼团活动归还库存量:{}", activityGroupId);
                log.error("拼团活动归还库存量报错:{}", e.fillInStackTrace());
                throw new CrmebException("拼团活动归还库存量报错!");
            }
            return;
        }

        //buyer的商品 查询attrvalue
        if(ProductTypeEnum.BUYER.getCode() == storeCartResponse.getProductInfo().getIsEurope()){
            StoreProductAttrValue apAttrValuePram = new StoreProductAttrValue();
            apAttrValuePram.setSourceSkuId(storeCartResponse.getProductInfo().getAttrInfo().getSourceSkuId());
            apAttrValuePram.setProductId(storeOrderInfo.getProductId());
            apAttrValuePram.setType(0);
            LambdaQueryWrapper<StoreProductAttrValue> lqw = new LambdaQueryWrapper<>();
            lqw.setEntity(apAttrValuePram);
            StoreProductAttrValue attrValue = dao.selectOne(lqw);
            if(null != attrValue){
                Integer stock = attrValue.getStock();
                LambdaUpdateWrapper<StoreProductAttrValue> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                lambdaUpdateWrapper.eq(StoreProductAttrValue::getProductId,storeOrderInfo.getProductId());
                lambdaUpdateWrapper.eq(StoreProductAttrValue::getSourceSkuId, attrValue.getSourceSkuId());
                lambdaUpdateWrapper.set(StoreProductAttrValue::getStock, attrValue.getStock()+storeCartResponse.getCartNum());
                //lambdaUpdateWrapper.set(StoreProductAttrValue::getSales, attrValue.getSales()-info.getInfo().getCartNum());
                update(lambdaUpdateWrapper);
                if(stock <= 0){
                    ThreadPoolUtils.getThread().submit(() -> storeProductService.updateProductMinPrice(storeProduct));
                }
            }
        }else{
            StoreProductAttrValue apAttrValuePram = new StoreProductAttrValue();
            apAttrValuePram.setProductId(storeOrderInfo.getProductId());
            apAttrValuePram.setBarCode(storeCartResponse.getProductInfo().getAttrInfo().getBarCode());
            apAttrValuePram.setSuk(storeCartResponse.getProductInfo().getAttrInfo().getSuk());
            apAttrValuePram.setSourceSkuId(storeCartResponse.getProductInfo().getAttrInfo().getSourceSkuId());
            LambdaQueryWrapper<StoreProductAttrValue> lqw = new LambdaQueryWrapper<>();
            lqw.setEntity(apAttrValuePram);
            StoreProductAttrValue attrValue = dao.selectOne(lqw);
            if(null != attrValue){
                Integer stock = attrValue.getStock();
                LambdaUpdateWrapper<StoreProductAttrValue> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                lambdaUpdateWrapper.eq(StoreProductAttrValue::getProductId, attrValue.getProductId());
                lambdaUpdateWrapper.eq(StoreProductAttrValue::getBarCode, attrValue.getBarCode());
                lambdaUpdateWrapper.eq(StoreProductAttrValue::getSuk, attrValue.getSuk());
                lambdaUpdateWrapper.set(StoreProductAttrValue::getStock, attrValue.getStock()+storeCartResponse.getCartNum());
                update(lambdaUpdateWrapper);
                if(stock <= 0){
                    ThreadPoolUtils.getThread().submit(() -> storeProductService.updateProductMinPrice(storeProduct));
                }
            }
        }

    }

    @Override
    public void updateValueSourceCost(List<Integer> productIdList) {
        dao.updateValueSourceCost(productIdList);
    }

    @Override
    public void updatePrice(List<Integer> productIdList, BigDecimal price) {
        dao.updatePrice(productIdList,price);
    }

    @Override
    public boolean updateBatchByQueryWrapper(Collection<StoreProductAttrValue> entityList, Function<StoreProductAttrValue, LambdaQueryWrapper> queryWrapperFunction) {
        String sqlStatement = this.getSqlStatement(SqlMethod.UPDATE);
        return this.executeBatch(entityList, DEFAULT_BATCH_SIZE, (sqlSession, entity) -> {
            MapperMethod.ParamMap param = new MapperMethod.ParamMap();
            param.put(com.baomidou.mybatisplus.core.toolkit.Constants.ENTITY, entity);
            param.put(com.baomidou.mybatisplus.core.toolkit.Constants.WRAPPER, queryWrapperFunction.apply(entity));
            sqlSession.update(sqlStatement, param);
        });
    }

}

